package com.winsdom.service.impl;

import com.winsdom.config.InMemoryConfig;
import com.winsdom.context.BaseContext;
import com.winsdom.domain.dto.collection.BillBaseDTO;
import com.winsdom.domain.dto.collection.BillDetailDTO;
import com.winsdom.domain.dto.collection.NotificationDefaultConfigDTO;
import com.winsdom.domain.vo.collection.*;
import com.winsdom.exception.IllegalArgumentException;
import com.winsdom.mapper.CollectionMapper;
import com.winsdom.result.PageResult;
import com.winsdom.result.Result;
import com.winsdom.service.CollectionService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@ConfigurationProperties(prefix = "collection")
public class CollectionServiceImpl implements CollectionService {

    @Resource
    private CollectionMapper collectionMapper;

    @Resource
    private InMemoryConfig inMemoryConfig;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Value("${collection.bill-notification-remark}")
    private String defaultBillNotificationRemark;





    @Override
    public Result<CustomerBillVO> getCustomerBillByCustomerId(Long customerId, String arrearsStatus) {
        if (customerId == null) {
            return Result.error("客户ID不能为空");
        }
        if (arrearsStatus == null || arrearsStatus.isEmpty()) {
            return Result.error("欠费状态不能为空");
        }
        // 1. 查询客户详细账单数据
        List<BillDetailDTO> detailList = collectionMapper.selectCustomerBillDetails(customerId, arrearsStatus);
        if (CollectionUtils.isEmpty(detailList)) {
            return Result.error("此用户没有相关账单数据");
        }

        // 2. 提取客户基本信息
        BillDetailDTO firstDto = detailList.get(0);
        CustomerBillVO customerBillVO = new CustomerBillVO();
        customerBillVO.setCustomerName(firstDto.getCustomerName());
        customerBillVO.setBuilding(firstDto.getBuilding());
        customerBillVO.setCollectorName(firstDto.getCollectorName());

        // 3. 按账期分组处理
        Map<String, List<BillDetailDTO>> periodGroup = detailList.stream()
                .collect(Collectors.groupingBy(BillDetailDTO::getBillingPeriod));

        // 4. 组装账期列表
        List<BillPeriodVO> periodVOList = new ArrayList<>();
        for (Map.Entry<String, List<BillDetailDTO>> entry : periodGroup.entrySet()) {
            List<BillDetailDTO> dtoList = entry.getValue();
            BillPeriodVO periodVO = new BillPeriodVO();

            // 账期聚合信息
            periodVO.setBillingPeriod(entry.getKey());
            // 计算此账期下所有账单的应收总和
            BigDecimal totalReceivable = dtoList.stream()
                    .map(BillDetailDTO::getReceivableAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            periodVO.setTotalReceivableAmount(totalReceivable);

            // 计算此账期下所有账单的欠费总和
            BigDecimal totalArrears = dtoList.stream()
                    .map(BillDetailDTO::getArrearsAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            periodVO.setTotalArrearsAmount(totalArrears);


            // 计算此账期下所有账单的退费抵扣总和
            BigDecimal refundDeduction = dtoList.stream()
                    .map(BillDetailDTO::getRefundDeduction)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            periodVO.setRefundDeduction(refundDeduction);

            // 计算此账期下所有账单的退费抵扣总和
            BigDecimal prepaidOffset = dtoList.stream()
                    .map(BillDetailDTO::getPrepaidOffset)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            periodVO.setPrepaidOffset(prepaidOffset);

            // 计算此账期下所有账单的退费抵扣总和
            BigDecimal lateFeeAmount = dtoList.stream()
                    .map(BillDetailDTO::getLateFeeAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            periodVO.setLateFeeAmount(lateFeeAmount);


            BillDetailDTO periodDto = dtoList.get(0);
            periodVO.setArrearsStatus(periodDto.getArrearsStatus());

            // 账单明细信息
            List<BillDetailVO> detailVOList = dtoList.stream().map(dto -> {
                BillDetailVO detailVO = new BillDetailVO();
                detailVO.setExpenditureName(dto.getExpenditureName());
                detailVO.setMeterNo(dto.getMeterNo());
                detailVO.setStartDate(dto.getStartDate());
                detailVO.setEndDate(dto.getEndDate());
                detailVO.setLastReading(dto.getLastReading());
                detailVO.setCurrentReading(dto.getCurrentReading());
                detailVO.setBuildingArea(dto.getBuildingArea());
                detailVO.setMeterRatio(dto.getMeterRatio());
                detailVO.setUsageAmount(dto.getUsageAmount());
                detailVO.setUnitPrice(dto.getUnitPrice());
                detailVO.setReceivableAmount(dto.getReceivableAmount());
                detailVO.setArrearsAmount(dto.getArrearsAmount());
                return detailVO;
            }).collect(Collectors.toList());

            periodVO.setDetails(detailVOList);
            periodVOList.add(periodVO);
        }

        customerBillVO.setPeriods(periodVOList);
        return Result.success(customerBillVO);
    }

    /**
     * 处理未结算账单
     * @param userId 用户ID
     * @param arrearsStatus 欠费状态，1：未结算，2：已结算
     * @param customerName 客户名称
     * @param building   楼盘名称
     * @param pageNum 页码
     * @param pageSize 每页记录数
     * @return
     */
    @Override
    public PageResult getBillList(Long userId, String arrearsStatus, String customerName,
                                  String building, int pageNum, int pageSize) {
        if (userId == null) {
            throw new IllegalArgumentException("用户ID不能为空");
        }
        if (arrearsStatus == null || (!"1".equals(arrearsStatus) && !"2".equals(arrearsStatus))) {
            throw new IllegalArgumentException("无效的欠费状态，仅支持1（未结算）和2（已结算）");
        }
        if (pageNum < 1) {
            throw new IllegalArgumentException("页码不能小于1");
        }
        if (pageSize < 1) {
            throw new IllegalArgumentException("每页记录数不能小于1");
        }
        // 1. 查询用户管辖的客户ID
        List<Long> customerIds = collectionMapper.selectCustomerIdsByUserId(userId);
        if (CollectionUtils.isEmpty(customerIds)) {
            return new PageResult(0L, new ArrayList<>(), pageNum, pageSize);
        }

        // 2. 查询账单基础信息
        Map<String, Object> params = new HashMap<>();
        params.put("building", building);
        params.put("customerName", customerName);
        params.put("arrearsStatus", arrearsStatus);
        List<BillBaseDTO> billBaseList = collectionMapper.selectBillBaseInfo(params);

        // 3. 按业务类型处理数据
        List<?> resultList;
        if ("1".equals(arrearsStatus)) {
            resultList = processUnsettledBills(billBaseList);
        } else if ("2".equals(arrearsStatus)) {
            resultList = processSettledBills(billBaseList);
        } else {
            throw new IllegalArgumentException("无效的欠费状态，仅支持1（未结算）和2（已结算）");
        }

        // 4. 分页处理（内存分页）
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, resultList.size());
        List<?> pageData = resultList.subList(startIndex, endIndex);

        return new PageResult((long) resultList.size(), pageData, pageNum, pageSize);
    }

    /**
     * 处理未结清账单列表
     * @param billBaseList 账单基础信息列表
     * @return
     */
    private List<UnsettledBillVO> processUnsettledBills(List<BillBaseDTO> billBaseList) {
        if (CollectionUtils.isEmpty(billBaseList)) {
            return new ArrayList<>();
        }

        // 按客户分组聚合数据
        Map<Long, List<BillBaseDTO>> customerGroup = billBaseList.stream()
                .collect(Collectors.groupingBy(bill -> bill.getCustomerId()));

        return customerGroup.entrySet().stream().map(entry -> {
            Long customerId = entry.getKey();
            List<BillBaseDTO> bills = entry.getValue();

            UnsettledBillVO vo = new UnsettledBillVO();
            vo.setCustomerId(customerId);
            vo.setCustomerName(bills.get(0).getCustomerName());
            vo.setBuilding(bills.get(0).getBuilding());

            // 计算应收总和与欠费总和
            BigDecimal totalReceivable = bills.stream()
                    .map(BillBaseDTO::getReceivableAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal totalArrears = bills.stream()
                    .map(BillBaseDTO::getArrearsAmount)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            vo.setTotalReceivableAmount(totalReceivable);
            vo.setTotalArrearsAmount(totalArrears);
            vo.setPaidAmount(totalReceivable.subtract(totalArrears)); // 实付金额 = 应收 - 欠费

            return vo;
        }).collect(Collectors.toList());
    }

    // 处理已结清账单列表
    private List<SettledBillVO> processSettledBills(List<BillBaseDTO> billBaseList) {
        if (CollectionUtils.isEmpty(billBaseList)) {
            return new ArrayList<>();
        }

        // 按账单编号分组（确保每个账单唯一）
        Map<String, BillBaseDTO> billGroup = billBaseList.stream()
                .collect(Collectors.toMap(BillBaseDTO::getBillNumber, bill -> bill, (a, b) -> a));

        return new ArrayList<>(billGroup.values()).stream().map(bill -> {
            SettledBillVO vo = new SettledBillVO();
            vo.setCustomerName(bill.getCustomerName());
            vo.setCustomerId(bill.getCustomerId());
            vo.setCollectorName(bill.getCollectorName());
            vo.setBillNumber(bill.getBillNumber());
            vo.setNotificationStatus(bill.getNotificationStatus());
            vo.setBillingPeriod(bill.getBillingPeriod());
            vo.setArrearsStatus(bill.getArrearsStatus());
            vo.setBuilding(bill.getBuilding());

            // 已结清账单的应收与欠费总和
            vo.setTotalReceivableAmount(bill.getReceivableAmount());
            vo.setTotalArrearsAmount(bill.getArrearsAmount());

            return vo;
        }).collect(Collectors.toList());
    }


    @Override
    @Transactional
    public void saveDefaultConfig(NotificationDefaultConfigDTO configDTO) {
        if (configDTO == null) {
            throw new IllegalArgumentException("通知默认配置不能为空");
        }
        configDTO.setPaymentNotifyEnabled(true);
        configDTO.setCollectionNotifyEnabled(true);

        // 检查是否已存在默认配置
        int count = collectionMapper.countDefaultConfig();

        if (count > 0) {
            // 更新现有默认配置
            collectionMapper.updateDefaultConfig(configDTO);
        } else {
            // 插入新的默认配置
            collectionMapper.insertDefaultConfig(configDTO);
        }

        // 2. 保存 billNotificationRemark 到 Redis 和内存
        inMemoryConfig.set(configDTO.getBillNotificationRemark());
    }


    @Override
    public NotificationDefaultConfigDTO getDefaultConfig() {
        NotificationDefaultConfigDTO config = collectionMapper.selectDefaultConfig();

        if (config == null) {
            throw new IllegalArgumentException("未找到客户通知默认配置");
        }
        // 从Redis获取billNotificationRemark
        String billNotificationRemark = redisTemplate.opsForValue().get("notification:billRemark");
        if (billNotificationRemark == null) {
            // 如果Redis中不存在，则使用sms.yml文件中的配置
            billNotificationRemark = defaultBillNotificationRemark;
        }
        // 从内存/Redis 获取最新的 billNotificationRemark
        config.setBillNotificationRemark(billNotificationRemark);
        return config;
    }


    /**
     * 获取当前用户ID
     * @return
     */
    @Override
    public Integer getCurrentUserId() {
        return BaseContext.getCurrentId(); // 直接从BaseContext获取用户ID
    }
}